package chapter19;

import org.springframework.data.redis.core.RedisTemplate;
import org.springframework.data.redis.core.script.DefaultRedisScript;
import org.springframework.data.redis.serializer.JdkSerializationRedisSerializer;
import redis.clients.jedis.Jedis;
import top.redis.Role;
import utils.ContextUtils;

import java.io.*;
import java.util.ArrayList;
import java.util.List;

public class Demo5 {

    public static void main(String[] args) {
//        setSimpleLuaByJedis();
//        setLuaBySpring();
         setLuaByByteArray();
    }

    /**
     * 将Lua脚本文件转为二进制字节数组，然后将字节数组传递到script脚本执行对象中
     * 然后将文件存储到Redis的缓存中，我们就只需要通过一个字符串标识就可以执行
     * Lua脚本文件了，避免大文件的网络传输降低redis的效率
     */
    public static void setLuaByByteArray(){
        RedisTemplate redisTemplate = ContextUtils.getBean("redisTemplate");
        Jedis jedis = (Jedis) redisTemplate.getConnectionFactory().getConnection().getNativeConnection();
        // 将需要执行的脚本lua，转化为二进制字节数组
        File file = new File("src/main/resources/script/file.lua");
        byte[] bytes = ContextUtils.getFileToByte(file);

        // 发送文件二进制给redis，这样redis就会返回shal标识
        byte[] sha1 = jedis.scriptLoad(bytes);

        // 通过返回的二进制标识进行执行脚本文件
        Object obj = jedis.evalsha(sha1, 2, "key1".getBytes(), "key2".getBytes(),
                "2".getBytes(), "4".getBytes());
        System.out.println(obj);
    }


    /**
     * 现实中需要存储一些复杂的对象
     * =》spring提供的RedisScript接口 对用的实现类 DefaultRedisScript
     */
    public static void setLuaBySpring(){
        RedisTemplate redisTemplate = ContextUtils.getBean("redisTemplate");
        // 定义默认脚本封装类
        DefaultRedisScript<Role> redisScript = new DefaultRedisScript<>();
        // 设置脚本
        redisScript.setScriptText("redis.call('set',KEYS[1],ARGV[1]) " +
                "return redis.call('get',KEYS[1])");
        // 定义操作的key列表
        List<String> keyList = new ArrayList<>();
        keyList.add("role1");
        // 需要序列化保存和读取的对象
        Role role = new Role();
        role.setId(1L);
        role.setRoleName("role_name_1");
        role.setNote("note_1");
        // 获得标识字符串
        String sha1 = redisScript.getSha1();
        System.out.println(sha1);
        // 设置返回结果类型，如果没有这句话，结果返回为空
        redisScript.setResultType(Role.class);
        // 定义序列化器
        JdkSerializationRedisSerializer serializer = new JdkSerializationRedisSerializer();
        /** 执行脚本
         * 第一个参数：RedisScript接口对象
         * 第二个参数：参数序列化器
         * 第三个参数：结果序列化器
         * 第四个参数：Ｒedis的key列表
         * 最后是：参数列表
         */
        Role obj = (Role) redisTemplate.execute(redisScript, serializer, serializer, keyList, role);
        System.out.println(obj);
    }


    /**
     * 存储的是一些简单的字符串
     */
    public static void setSimpleLuaByJedis(){
        RedisTemplate redisTemplate = ContextUtils.getBean("redisTemplate");
        Jedis jedis = (Jedis) redisTemplate.getConnectionFactory().getConnection().getNativeConnection();

        // 执行简单的脚本
        String helloJava = (String) jedis.eval("return 'hello java'");
        System.out.println(helloJava);

        // 执行带参数的脚本
        jedis.eval("redis.call('set',KEYS[1],ARGV[1])", 1, "lua-key3", "lua-value3");
        String luakey = jedis.get("lua-key4");
        System.out.println(luakey);

        // 缓存脚本，返回sha1签名标识
        String sha1 = jedis.scriptLoad("redis.call('set',KEYS[1],ARGV[1])");
        // 通过标识 执行脚本
        jedis.evalsha(sha1,1,new String[]{"sha-key5","sha-val5"});
        //  获取执行脚本后的数据
        String shaVal = jedis.get("sha-key5");
        System.out.println(shaVal);
        // 关闭连接
        jedis.close();
    }

}
